#pragma once
#include <iostream>
#include <cstring>
#include <cassert>
#include <functional>
#include <string>
#include <pthread.h>


class Thread;

class Context
{
public:
    Context()
        :_this(nullptr)
        ,_args(nullptr)
    {}
    ~Context()
    {}

public:
    Thread *_this;
    void *_args;
};



class Thread
{
public:
    typedef std::function<void*(void*)> func_t;
    // typedef void*(*func_t)(void*);

    const int num = 128;
     
public:
    Thread(func_t func, void *args = nullptr, int number = 0)
        :_func(func)
        ,_args(args)
    {
        // _name += "thread-";
        // _name += std::to_string(number);

        char namebuffer[num];
        snprintf(namebuffer, sizeof(namebuffer), "thread-%d", number);
        _name = namebuffer;
        start();
    }

    ~Thread()
    {
        // do nothing
    }

    void join()
    {
        int n = pthread_join(_tid, nullptr);
        assert(0 == n);
        (void)n;
    }

private:

    void *run(void *args)
    {
        return _func(args);
    }

    static void *start_routine(void *args)
    {
        Context *ctx = static_cast<Context*>(args);
        ctx->_this->run(ctx->_args);
        delete ctx;
    }

    void start()
    {
        // int n = pthread_create(&_tid, nullptr, _func, _args);
        Context *ctx = new Context();
        ctx->_this = this;
        ctx->_args = _args;

        int n = pthread_create(&_tid, nullptr, start_routine, (void*)ctx);
        assert(0 == n);
        (void)n;
    }

private:
    std::string _name;
    pthread_t _tid;
    func_t _func;
    void *_args;
};